﻿using DScheme.DancerClasses;
using Gif.Components;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DScheme
{
    public partial class Form1 : Form
    {

        /// <summary>размер одного поинта в пикселях</summary>
        const int POINT_SIZE = 10;

        List<Dancer> dl = new List<Dancer>();

        public Form1()
        {
            InitializeComponent();

            dl.Add(new Dancer(DancerSex.K, 0, new Point(100, 180)));
            dl.Add(new Dancer(DancerSex.D, 1, new Point(100, 80)) { Angle = 180 });
            dl.Add(new Dancer(DancerSex.D, 3, new Point(100, 280)));

            // dl.Add(new Dancer(DancerSex.D, 0, new Point(100, 280)));

            /* dl.Add(new Dancer(DancerSex.K, 0, new Point(100, 200)));
             dl.Add(new Dancer(DancerSex.K, 3, new Point(100, 200)));

             // тест круга
             //dl[0].al.Add(new DancerActionMoveByCircle(dl[0].PosP, 50, 180, 360, false, 0, 2));

             // тест еллипса
             dl[0].al.Add(new DancerActionMoveByEllipse(dl[0].PosP, 50, 80, 45, 360, false, 0, 2));*/

            im.Image = new Bitmap(im.Width, im.Height);
            RenderField();
        }

        const bool ShowPosInfo = false;

        void RenderField()
        {
            im.Image = RenderFrame(im.Width, im.Height, elaptedTimeTacts);
            im.Refresh();
        }

        Bitmap RenderFrame(int w, int h, double elaptedTimeTacts)
        {
            List<Color> clrL = new List<Color>()
            {
                Color.Black,
                Color.Blue,
                Color.Green,
                Color.Maroon,
                Color.Red
            };
            Bitmap bmp = new Bitmap(w, h);

            using (Graphics gr = Graphics.FromImage(bmp))
            {
                gr.Clear(Color.FromArgb(240, 220, 190));
                Render8(gr);
                foreach (Dancer dancer in dl)
                {
                    System.Drawing.Drawing2D.Matrix m0 = gr.Transform;
                    System.Drawing.Drawing2D.Matrix m = new System.Drawing.Drawing2D.Matrix();
                    m.RotateAt((float)dancer.Angle, new PointF((float)dancer.Pos.X, (float)dancer.Pos.Y));
                    gr.Transform = m;
                    gr.DrawImage(GetDancerBmp(dancer.Sex, dancer.Num), (float)dancer.Pos.X - 25, (float)dancer.Pos.Y - 25);
                    gr.Transform = m0;

                    if (ShowPosInfo)
                    {
                        gr.DrawString(Math.Round(dancer.Pos.X, 1).ToString("F1") + ":" + Math.Round(dancer.Pos.Y, 1).ToString("F1") + " | " + Math.Round(dancer.Angle, 1).ToString("F1") + "°", Font, Brushes.Black, (float)dancer.Pos.X + 20, (float)dancer.Pos.Y - 20);
                    }
                }
                /* gr.DrawString(elaptedTimeS.ToString("F2"), Font, Brushes.White, 0, 0);
                 if (mPnt.X != -1)
                     gr.DrawString(mPnt.X + ":" + mPnt.Y, Font, Brushes.White, im.Width - 50, 0);*/
                double t = (elaptedTimeTacts) / 3;
                Point tP = new Point(140, 170);

                if (t >= 1 && t < 9)
                {
                    DrawStringW(gr, ((int)t).ToString(), new Font("Arial", 16, FontStyle.Bold), tP.X, tP.Y);
                    if ((t - ((int)t)) >= 0.333) DrawStringW(gr, "2", new Font("Arial", 10, FontStyle.Bold), tP.X + 18, tP.Y + 8);
                    if ((t - ((int)t)) >= 0.666) DrawStringW(gr, "3", new Font("Arial", 10, FontStyle.Bold), tP.X + 30, tP.Y + 8);
                }
            }
            return bmp;
        }

        void DrawStringW(Graphics gr, string str, Font font, int x, int y)
        {
            gr.DrawString(str, font, Brushes.Black, x + 1, y + 1);
            gr.DrawString(str, font, Brushes.White, x, y);
        }

        Bitmap GetDancerBmp(DancerSex dancerSex, int dancerNum)
        {
            Dictionary<int, Bitmap> damaImages = new Dictionary<int, Bitmap>()
            {
                {0, Properties.Resources.D1},
                {1, Properties.Resources.D_red},
                {2, Properties.Resources.D_green},
                {3, Properties.Resources.D_blue}
            };

            if (dancerSex == DancerSex.D) return damaImages[dancerNum];
            else return Properties.Resources.K1;

            /* Bitmap bmp = new Bitmap(50, 50);

             using (Graphics gr = Graphics.FromImage(bmp))
             {
                 gr.FillEllipse(Brushes.Blue, 2, 10, 36, 20);
                 gr.FillEllipse(Brushes.Blue, 0, 12, 10, 10);
                 gr.FillEllipse(Brushes.Blue, 30, 12, 10, 10);
                 gr.DrawEllipse(Pens.Black, 2, 10, 36, 20);
                 gr.FillEllipse(Brushes.Wheat, 12, 11, 16, 16);
                 gr.DrawEllipse(Pens.Blue, 12, 11, 16, 16);
                 gr.FillRectangle(Brushes.Blue, 18, 13, 1, 1);
                 gr.FillRectangle(Brushes.Blue, 22, 13, 1, 1);
             }

             return bmp;*/
        }

        void Render8(Graphics gr)
        {
            gr.DrawArc(Pens.White, new Rectangle(50, 30, 100, 120), 135, 270);
            gr.DrawArc(Pens.White, new Rectangle(50, 210, 100, 120), 315, 270);
            gr.DrawLine(Pens.White, 62, 129, 138, 231);
            gr.DrawLine(Pens.White, 138, 129, 62, 231);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            basedElapsedTime = 0;
            elaptedTimeTacts = 0;

            List<DancerMover> dmL = new List<DancerMover>()
               {
                   new DancerMover(dl[0]),
                   new DancerMover(dl[1]),
                   new DancerMover(dl[2])
            };

            dl[0].Pos = new Point(100, 180);
            dl[1].Pos = new Point(100, 80);
            dl[2].Pos = new Point(100, 280);

            dmL[0].RotateTo(0, 3, true, true);
            dmL[1].RotateTo(180, 3, true, true);
            dmL[2].RotateTo(0, 3, true, true);
            dmL[0].NormalizeAngle();
            dmL[1].NormalizeAngle();
            dmL[2].NormalizeAngle();
            dmL[2].TimeTo(3);

            // для восьмерки (со смещением)
            {
                dmL[0].LineTo(new Point(62, 129), 2, false);
                dmL[0].RotateOn(-25, 1); dmL[0].TimeTo(1);
                dmL[0].EllipseTo(50, 60, 50, false, 270, 8, false);
                dmL[0].RotateOn(250, 8);
                dmL[0].LineTo(new Point(62, 231), 3);
                dmL[0].EllipseTo(50, 60, 50, true, 270, 8, false);
                dmL[0].RotateOn(-260, 8);
                dmL[0].LineTo(new Point(100, 180), 1.5, false);
                dmL[0].RotateTo(-90, 2);

                dmL[1].EllipseTo(60, 70, 225, false, 90.3, 4, false);
                dmL[1].RotateOn(-10, 1);
                dmL[1].RotateOn(45, 3);
                dmL[1].LineTo(new Point(62, 231), 2);
                dmL[1].EllipseTo(50, 60, 50, true, 270, 8, false);
                dmL[1].RotateOn(-260, 8);
                dmL[1].LineTo(new Point(62, 129), 3.5);
                dmL[1].EllipseTo(50, 60, 50, false, 90, 3, false);
                dmL[1].RotateOn(90, 3);
                dmL[1].CircleTo(23.8, 138, false, 180, 2.5, false);
                dmL[1].RotateTo(270, 2.5);
                dmL[1].LineTo(new Point(100, 80), 0.01);

                dmL[2].EllipseTo(45, 50, 200, true, 110, 3.5, false);
                dmL[2].RotateOn(25, 1);
                dmL[2].RotateOn(-65, 2.5);
                dmL[2].LineTo(new Point(62, 129), 3);
                dmL[2].EllipseTo(50, 60, 50, false, 270, 8, false);
                dmL[2].RotateOn(260, 8);
                dmL[2].LineTo(new Point(100, 180), 1.75);
                dmL[2].EllipseTo(50, 57.7, 30, true, 120, 3.75, false);
                dmL[2].RotateOn(-50, 1.5);
                dmL[2].TimeTo(0.75);
                dmL[2].RotateTo(270, 1.5);
                dmL[2].LineTo(new Point(100, 280), 0.01);

                dmL[0].NormalizeAngle();
                dmL[1].NormalizeAngle();
                dmL[2].NormalizeAngle();
            }

            /* dl[0].Angle = 90;
             dmL[0].TimeTo(1);
             dmL[0].RotateTo(0, 3, true, true);*/

            startTime = DateTime.Now;
            tmrMain.Enabled = true;
            //TestExecuteActions();
        }

        DateTime startTime = DateTime.Now;
        double basedElapsedTime = 0;
        double elaptedTimeTacts = 0;
        double tactLen = 180; // количество тактов/счетов в минуту

        private void tmrMain_Tick(object sender, EventArgs e)
        {
            elaptedTimeTacts = basedElapsedTime + (DateTime.Now - startTime).TotalSeconds * (tactLen / 60.0);
            foreach (Dancer dancer in dl)
                dancer.ExecuteActions(elaptedTimeTacts);
            RenderField();
        }

        double elaptedTimeS_ForTest = 0;
        void TestExecuteActions()
        {
            elaptedTimeS_ForTest = 2;
            for (int i = 0; i < 20; i++)
            {
                elaptedTimeS_ForTest += 0.1;
                foreach (Dancer dancer in dl)
                    dancer.ExecuteActions(elaptedTimeS_ForTest);
                RenderField();
            }
        }

        class BmpForGif
        {
            public Bitmap Bmp;
            /// <summary>время показа кадра</summary>
            public int Delay;

            public BmpForGif(Bitmap bmp, int delay)
            {
                Bmp = bmp;
                Delay = delay;
            }
        }

        void RecordDance()
        {
            List<DancerMover> dmL = new List<DancerMover>()
               {
                   new DancerMover(dl[0]),
                   new DancerMover(dl[1]),
                   new DancerMover(dl[2])
            };

            dl[0].Pos = new Point(100, 180);
            dl[1].Pos = new Point(100, 80);
            dl[2].Pos = new Point(100, 280);
            dl[0].Angle = 270;
            dl[1].Angle = 270;
            dl[2].Angle = 270;

            dmL[0].RotateTo(0, 3, true, true);
            dmL[1].RotateTo(180, 3, true, true);
            dmL[2].RotateTo(0, 3, true, true);
            dmL[0].NormalizeAngle();
            dmL[1].NormalizeAngle();
            dmL[2].NormalizeAngle();
            dmL[2].TimeTo(3);

            // для восьмерки (со смещением)
            {
                dmL[0].LineTo(new Point(62, 129), 2, false);
                dmL[0].RotateOn(-25, 1); dmL[0].TimeTo(1);
                dmL[0].EllipseTo(50, 60, 50, false, 270, 8, false);
                dmL[0].RotateOn(250, 8);
                dmL[0].LineTo(new Point(62, 231), 3);
                dmL[0].EllipseTo(50, 60, 50, true, 270, 8, false);
                dmL[0].RotateOn(-260, 8);
                dmL[0].LineTo(new Point(100, 180), 1.5, false);
                dmL[0].RotateTo(-90, 2);

                dmL[1].EllipseTo(60, 70, 225, false, 90.3, 4, false);
                dmL[1].RotateOn(-10, 1);
                dmL[1].RotateOn(45, 3);
                dmL[1].LineTo(new Point(62, 231), 2);
                dmL[1].EllipseTo(50, 60, 50, true, 270, 8, false);
                dmL[1].RotateOn(-260, 8);
                dmL[1].LineTo(new Point(62, 129), 3.5);
                dmL[1].EllipseTo(50, 60, 50, false, 90, 3, false);
                dmL[1].RotateOn(90, 3);
                dmL[1].CircleTo(23.8, 138, false, 180, 2.5, false);
                dmL[1].RotateTo(270, 2.5);
                dmL[1].LineTo(new Point(100, 80), 0.01);

                dmL[2].EllipseTo(45, 50, 200, true, 110, 3.5, false);
                dmL[2].RotateOn(25, 1);
                dmL[2].RotateOn(-65, 2.5);
                dmL[2].LineTo(new Point(62, 129), 3);
                dmL[2].EllipseTo(50, 60, 50, false, 270, 8, false);
                dmL[2].RotateOn(260, 8);
                dmL[2].LineTo(new Point(100, 180), 1.75);
                dmL[2].EllipseTo(50, 57.7, 30, true, 120, 3.75, false);
                dmL[2].RotateOn(-50, 1.5);
                dmL[2].TimeTo(0.75);
                dmL[2].RotateTo(270, 1.5);
                dmL[2].LineTo(new Point(100, 280), 0.01);

                dmL[0].NormalizeAngle();
                dmL[1].NormalizeAngle();
                dmL[2].NormalizeAngle();

                dmL[2].RotateTo(270, 3);
            }

            bool inAction = true;
            double timeSec = 0;
            int stepMs = 50;

            List<BmpForGif> frmL = new List<BmpForGif>();


            while (inAction)
            {
                inAction = false;
                foreach (Dancer dancer in dl)
                    dancer.ExecuteActions(timeSec * 2.0);
                inAction = dl.Exists(d => !d.DoneAll);
                frmL.Add(new BmpForGif(RenderFrame(200, 360, timeSec * 2.0), stepMs));
                timeSec += stepMs / 1000.0;
            }

            SaveGif(frmL);
            MessageBox.Show("анимация создана");
        }

        void SaveGif(List<BmpForGif> frameList)
        {
            string gifFilePath = Path.Combine(Application.StartupPath, DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff") + ".gif");
            using (MemoryStream ms = new MemoryStream())
            {
                AnimatedGifEncoder e = new AnimatedGifEncoder();
                e.Start(ms);
                e.SetDelay(500);
                //-1:no repeat,0:always repeat
                e.SetRepeat(0);
                foreach (BmpForGif frame in frameList)
                {
                    e.SetDelay(frame.Delay);
                    e.AddFrame(frame.Bmp);
                }
                e.Finish();
                File.WriteAllBytes(gifFilePath, ms.ToArray());
            }
        }

        Point mPnt = new Point(-1, -1);
        private void im_MouseMove(object sender, MouseEventArgs e)
        {
            mPnt = im.PointToClient(Cursor.Position);
            RenderField();
        }

        int ang = 0;
        private void timer1_Tick(object sender, EventArgs e)
        {
            using (Graphics gr = Graphics.FromImage(im.Image))
            {
                gr.Clear(Color.LightGray);

                ang += 5;
                Bitmap bmp = GetDancerBmp(DancerSex.K, 1);
                System.Drawing.Drawing2D.Matrix m = new System.Drawing.Drawing2D.Matrix();
                m.RotateAt(ang, new Point(120, 120));
                gr.Transform = m;
                gr.DrawImage(bmp, (float)100, (float)100);
            }
            im.Refresh();
        }

        private void btnCreateGif_Click(object sender, EventArgs e)
        {
            RecordDance();
        }
    }
}
